package com.codinghero.zqlb.spider.bo;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import com.codinghero.util.ArrayUtils;
import com.codinghero.util.DateUtils;
import com.codinghero.zqlb.match.DateSortableComparator;
import com.codinghero.zqlb.match.RawMatch;
import com.codinghero.zqlb.match.SoccerMatch;
import com.codinghero.zqlb.spider.FYZBSpider;
import com.codinghero.zqlb.spider.ZZBSpider;
import com.codinghero.zqlb.spider.dao.MatchDao;
import com.codinghero.zqlb.spider.handler.HotMatchFilterHandler;

public class MatchBo {
	
	private MatchDao matchDao = new MatchDao();
	private ZZBSpider zzbSpider = new ZZBSpider();
	private FYZBSpider fyzbSpider = new FYZBSpider();
	
	public List<SoccerMatch> getAllMatches() {
		try {
			matchDao.connect();
			return matchDao.getAllMatches();
		} catch (SQLException e) {
			e.printStackTrace();
			return new ArrayList<SoccerMatch>();
		} finally {
			matchDao.close();
		}
	}
	
	public List<SoccerMatch> getAllValidMatches() {
		try {
			matchDao.connect();
			return matchDao.getAllValidMatches();
		} catch (SQLException e) {
			e.printStackTrace();
			return new ArrayList<SoccerMatch>();
		} finally {
			matchDao.close();
		}
	}
	
	public List<SoccerMatch> getMatchesByTypeIds(Integer[] typeIds) {
		try {
			matchDao.connect();
			return matchDao.getMatchesByTypeIds(typeIds);
		} catch (SQLException e) {
			e.printStackTrace();
			return new ArrayList<SoccerMatch>();
		} finally {
			matchDao.close();
		}
	}

	public List<ArrayList<SoccerMatch>> getHotMatches(final int days, final int[] timePeriods) {
		
		// startDate=yyyy-MM-dd 12:00:00, endDate=yyyy-MM-dd 11:59:59
		String startDate = DateUtils.getDateStr(new Date(), "yyyy-MM-dd " + timePeriods[0] + ":00:00");
		Calendar calendar = Calendar.getInstance();
		calendar.add(Calendar.DAY_OF_MONTH, days);
		String endDate = DateUtils.getDateStr(calendar.getTime(), "yyyy-MM-dd " + (timePeriods[0] - 1) + ":59:59");
		
		try {
			matchDao.connect();
			List<SoccerMatch> matches = matchDao.getMatchesByDate(startDate, endDate);
			matchDao.close();
			
			List<ArrayList<SoccerMatch>> result = this.splitByTimeSpan(matches, days, timePeriods);
			for (ArrayList<SoccerMatch> periodMatches : result) {
				new HotMatchFilterHandler().handle(periodMatches);
			}
			return result;
		} catch (SQLException e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		} finally {
			matchDao.close();
		}
	}
	
	private List<ArrayList<SoccerMatch>> splitByTimeSpan(List<SoccerMatch> matches, int days, int[] hourSpan) {
		List<ArrayList<SoccerMatch>> result = new ArrayList<ArrayList<SoccerMatch>>();
		Collections.sort(matches, new DateSortableComparator());
		Date[] timeSpans = new Date[days * hourSpan.length];
		for (int i = 0; i < days * hourSpan.length; i++) {
			Calendar calendar = Calendar.getInstance();
			calendar.add(Calendar.DAY_OF_MONTH, (i + 1) / hourSpan.length);
			calendar.set(Calendar.HOUR_OF_DAY, hourSpan[(i + 1) % hourSpan.length]);
			calendar.set(Calendar.MINUTE, 0);
			calendar.set(Calendar.SECOND, 0);
			timeSpans[i] = calendar.getTime();
		}

		result.add(new ArrayList<SoccerMatch>());
		for (int i = 0, tsi = 0; i < matches.size(); i++) {
			SoccerMatch match = matches.get(i);
			while (DateUtils.compareTo(match.getStartDate(), timeSpans[tsi]) >= 0) {
				result.add(new ArrayList<SoccerMatch>());
				tsi++;
			}
			result.get(tsi).add(match);
		}
		return result;
	}
	
	public void insertTempMatch(List<SoccerMatch> list) {
		try {
			matchDao.connect();
			matchDao.startTransaction();
			for (SoccerMatch match : list) {
				matchDao.insertTempMatch(match);
			}
			matchDao.commit();
		} catch (SQLException e) {
			matchDao.rollback();
			e.printStackTrace();
		} finally {
			matchDao.close();
		}
	}

	public int[] importMatch(List<SoccerMatch> list) {
		
		try {
			matchDao.connect();
			matchDao.truncateTempMatch();
		} catch (SQLException e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		} finally {
			matchDao.close();
		}
		this.insertTempMatch(list);
		
		try {
			matchDao.connect();
			matchDao.startTransaction();
			int[] affectedNums1 = matchDao.updateMatchTime();
			int[] affectedNums2 = matchDao.deleteDupMatches();
			int affectedNum = matchDao.insertTempToMatch();
			matchDao.commit();
			return ArrayUtils.merge(
					ArrayUtils.merge(affectedNums1, affectedNums2),
					affectedNum);
		} catch (SQLException e) {
			matchDao.rollback();
			e.printStackTrace();
			return new int[] {};
		} finally {
			matchDao.close();
		}
	}
	
	public int[] backHistoryMatches() {
		try {
			matchDao.connect();
			matchDao.startTransaction();
			Date now = new Date();
			int affectedNum1 = matchDao.insertMatchToHistory(now);
			int affectedNum2 = matchDao.deleteHistoryMatch(now);
			matchDao.commit();
			return new int[] { affectedNum1, affectedNum2 };
		} catch (SQLException e) {
			matchDao.rollback();
			e.printStackTrace();
			return new int[] { 0, 0 };
		} finally {
			matchDao.close();
		}
	}
	
	public int updateMatchStatusByIds(String[] ids, int status) {
		try {
			matchDao.connect();
			matchDao.startTransaction();
			int affectedNum = matchDao.updateMatchStatusByIds(ids, status);
			matchDao.commit();
			return affectedNum;
		} catch (SQLException e) {
			matchDao.rollback();
			e.printStackTrace();
			return 0;
		} finally {
			matchDao.close();
		}
	}
	
	public int[] spide() {
		List<SoccerMatch> zzbList = zzbSpider.parse("zhibo8.cc", "UTF-8");
		List<RawMatch> fyzbList = fyzbSpider.parse("www.fengyunzhibo.com/airlist/index.jsp", "UTF-8");
		Collections.sort(zzbList, new DateSortableComparator());
		Collections.sort(fyzbList, new DateSortableComparator());
		this.mergeZZBAndFYZB(zzbList, fyzbList);
		return new MatchBo().importMatch(zzbList);
	}
	
	private void mergeZZBAndFYZB(List<SoccerMatch> zzbList, List<RawMatch> fyzbList) {
//		Iterator<RawMatch> iter = fyzbList.iterator();
//		while (iter.hasNext()) {
//			RawMatch fyzbMatch = iter.next();
//			if (fyzbMatch.getTypeId() == null || fyzbMatch.getTypeId() == 0)
//				iter.remove();
//		}

		for (int zzbIndex = 0, fyzbIndex = 0; zzbIndex < zzbList.size() && fyzbIndex < fyzbList.size(); ) {
			SoccerMatch zzbMatch = zzbList.get(zzbIndex);
			RawMatch fyzbMatch = fyzbList.get(fyzbIndex);
			final long HALF_HOUR = 1810000; 
			// 两套数据源的同一场比赛时间误差是半小时（闭区间）
			if (fyzbMatch.getStartDate().getTime() <= zzbMatch.getStartDate().getTime() + HALF_HOUR
					&& fyzbMatch.getStartDate().getTime() >= zzbMatch.getStartDate().getTime() - HALF_HOUR) {
				int tempFyzbIndex = fyzbIndex;
				
				// 如果时间相近，且比赛类型和比赛球队相同，则添加直播频道
				while(fyzbMatch.getStartDate().getTime() <= zzbMatch.getStartDate().getTime() + HALF_HOUR
						&& fyzbMatch.getStartDate().getTime() >= zzbMatch.getStartDate().getTime() - HALF_HOUR) {
					if (fyzbMatch.getRawStr().contains(zzbMatch.getTeam1Name())
							&& fyzbMatch.getRawStr().contains(zzbMatch.getTeam2Name())
							&& (fyzbMatch.getTypeId() == null || fyzbMatch.getTypeId().equals(zzbMatch.getTypeId()))) {
						zzbMatch.getChannelIdSet().addAll(fyzbMatch.getChannelIdSet());
						zzbMatch.refreshChannelIds();
					}
					if (++tempFyzbIndex < fyzbList.size())
						fyzbMatch = fyzbList.get(tempFyzbIndex);
					else 
						break;
				}
				zzbIndex++;
			} else if (fyzbMatch.getStartDate().getTime() > zzbMatch.getStartDate().getTime() + HALF_HOUR)
				zzbIndex++;
			else if (fyzbMatch.getStartDate().getTime() < zzbMatch.getStartDate().getTime() - HALF_HOUR)
				fyzbIndex++;
			else
				throw new RuntimeException("zzb & fyzb merge error, match time error");
		}
	}
}
